import { app, BrowserWindow, net } from 'electron'
import path from 'node:path'
import fs from 'fs-extra';
import store from './store'
import { spawn } from 'node:child_process';
import ssri from 'ssri';

const APP_NAME = app.getName();
const EXE_PATH = path.dirname(app.getPath('exe'))
const APPS_PATH = path.join(app.getPath('userData'), "apps")
const TEMP_PATH = path.join(app.getPath("temp"), APP_NAME)
const UPDATER_EXE_PATH = path.join(EXE_PATH, "updater.exe")

// base url
const baseUrl = () => {
  return "https://gitee.com"
}

// app list url
const appUrl = () => {
  return `${baseUrl()}/${APP_NAME}/${APP_NAME}/raw/master/app.json`
}

// merge app list
const mergeAppData = (data: any) => {
  let oldData: any = store.get("apps", {});
  let obj: any = {};
  for (let i = 0; i < data.length; i++) {
    let status = "";
    if (oldData[data[i].name]) {
      data[i].currentVersion = oldData[data[i].name].version
      data[i].currentChecksum = oldData[data[i].name].checksum
      if (data[i].checksum !== data[i].currentChecksum) {
        status = "upgrade";
      }
    } else {
      status = "download"
    }
    data[i].status = status
    obj[data[i].name] = data[i]
  }
  store.set("apps", obj);
}

// load data
const loadData = () => {
  return new Promise((resolve) => {
    const doResolve = () => {
      resolve(store.all())
    }
    net.fetch(appUrl()).then((response: any) => {
      if (!response.ok) {
        doResolve()
        return
      }
      response.json().then((body: any) => {
        mergeAppData(body)
        doResolve()
      }).catch((err: any) => {
        console.error(err)
        doResolve()
      })
    }).catch((err: any) => {
      console.error(err)
      doResolve()
    })
  })
}

// Upgrade and relaunch
const upgrade = (_: any, name: string) => {
  return new Promise((resolve) => {
    let data: any = store.get(`apps.${name}`, {});
    let filename = tempFileName(data)
    if (name === "main") {
      relaunch(filename, EXE_PATH)
    } else {
      const child = spawn(UPDATER_EXE_PATH, [APPS_PATH], { windowsHide: true })
      child.stderr.on('data', (data: any) => {
        console.error(data);
      });
      child.on('close', () => {
        resolve(store.all())
      });
    }
  })
}

const tempFileName = (data: any) => {
  return path.join(TEMP_PATH, data.checksum)
}

// Download file
const download = (_: any, name: string) => {
  const cb = (type: string, message: any) => {
    console.log(name, type, message)
  }
  let data: any = store.get(`apps.${name}`, {});
  const request = net.request(data.download)
  let filename = tempFileName(data)
  if (fs.pathExistsSync(filename)) {
    // let checksum = ssri.fromData(fs.readFileSync(filename)).toString();    
    if (ssri.checkData(fs.readFileSync(filename), data.checksum) === false) {// checksum file
      fs.removeSync(filename)
    } else {
      cb("progress", { percent: 100, finish: 0, total: 0 })
      return
    }
  }
  request.on('response', (response: Electron.IncomingMessage) => {
    if (response.statusCode !== 200) {
      cb("error", response.statusMessage)
      return
    }
    let total = Number(response.headers["content-length"] || 0)
    let finish = 0;
    response.on('data', (chunk: Buffer) => {
      try {
        fs.appendFileSync(filename, chunk)
      } catch (err: any) {
        cb("error", err.message)
      }
      finish += chunk.length
      cb("progress", { percent: parseInt((finish / total * 100).toString()), finish: finish, total: total })
    })
    response.on('end', () => {
      cb("progress", { percent: parseInt((finish / total * 100).toString()), finish: finish, total: total })
    })
  })
  request.on('error', (err: Error) => {
    cb("error", err.message)
  })
  request.end()
}

// main relaunch
const relaunch = (filename: string, dir: string) => {
  BrowserWindow.getAllWindows().forEach(w => w.destroy());
  app.relaunch({ execPath: UPDATER_EXE_PATH, args: [app.getPath('exe'), filename, dir] });
  app.quit();
}

export default { loadData, upgrade, download }